package com.espirit.eap.manager;

import java.util.Calendar;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.espirit.eap.sa.LoginUser;
import com.googlecode.cswish.model.ModelInfo;
import com.googlecode.cswish.model.PropertyInfo;
import com.googlecode.cswish.struts.spring.BeanIntrospector;
import com.googlecode.cswish.struts.spring.CacheService;
import com.googlecode.cswish.struts.spring.CacheService.Wrapper;
import com.googlecode.cswish.struts.spring.Executor;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.util.ClassUtil;
import com.googlecode.cswish.util.bean.ModelUtil;

@Service
public class SystemLogService {

	@Resource
	private GenericService genericService;
	
	@Resource
	protected BeanIntrospector beanIntrospector;
	
	@Resource
	CacheService cacheService;
	
	private Wrapper<Executor<Object, Object[]>> systemLogRegular;
	
	@PostConstruct
	private void init() {
		Wrapper wrapper = cacheService.newVar(Executor.class);
		systemLogRegular = wrapper;
	}
	
	@Async
	public void add(String actionName, Map<String, String[]> parametersMap, LoginUser loginUser, String ip) throws NumberFormatException, ClassNotFoundException{
		String modelName = beanIntrospector.getSimpleName(actionName);
		String className = beanIntrospector.getModelName(modelName);
		String methodName = StringUtils.uncapitalize(actionName.substring(actionName.lastIndexOf('.') + 1, actionName.length() - 6));
		String modelId = null;
		String fromMenu = null;
		Set<String> keySet = parametersMap.keySet();
		Iterator<String> iterator = keySet.iterator();
		while(iterator.hasNext()){
			String name = iterator.next();
			if ("model.id".equals(name)){
				String[] value = parametersMap.get(name);
				modelId = value[0];
			}
			if ("fromMenu".equals(name)){
				String[] value = parametersMap.get(name);
				fromMenu =  value[0];
			}
		}
		String parameter = modelId == null ? null : "{model.id=" + modelId + "}";
		
		if (!StringUtils.isEmpty(modelId) && "update".equals(methodName)){
    	    Object oldModel = genericService.load(ClassUtil.getClass(className), Integer.valueOf(modelId));
    	    ModelInfo mi = beanIntrospector.getModelInfo(oldModel.getClass().getName());
    	    String logSource = null;
    	    if (oldModel instanceof SystemLogAware){
    	    	SystemLogAware aware = (SystemLogAware) oldModel;
    	    	logSource = aware.logSource();
    	    } else {
    	    	PropertyInfo pi = mi.getProperty("name");
    	    	if (pi != null){
    	    	   logSource = pi.getName();
    	    	}
    	    }
    	    if (logSource != null){
    	    	StringBuffer sb = new StringBuffer();
    	    	String src = (String)ModelUtil.getProperty(oldModel, logSource);
    	    	if (src != null){
    	    		sb.append((String)ModelUtil.getProperty(oldModel, logSource)).append(":");
    	    	}
    	    	iterator = keySet.iterator();
    	    	
    	    	//TODO:null value not post,perhaps need use property iterator.
    	    	while(iterator.hasNext()){
    				String name = iterator.next();
    				if (name.startsWith("model.")){
    					String modelProperty = name.substring(6);
    					Object prev = ModelUtil.getProperty(oldModel, modelProperty);
    	    			String[] cur =  parametersMap.get(name);
    	    			String curStr = null;
    	    			if (cur != null){
    	    				curStr = cur[0];
    	    			}
    		    		if (cur == null && prev == null) continue;
    					
    					if (cur != null && prev == null){
    						sb.append(modelProperty).append("[ ->").append(curStr).append("] ");
    					} else if (cur == null && prev != null) {
    						sb.append(modelProperty).append("[").append(prev.toString()).append("-> ] ");//   ->").append(cur.toString()).append("] ");
    					} else {
    						if (!curStr.equals(prev.toString())){
    							sb.append(modelProperty).append("[").append(prev.toString()).append("->").append(curStr).append("] ");
    						}
    					}
    				}
    			}
    	    	String val = sb.toString();
    	    	if (!StringUtils.isEmpty(val)){
    	    		parameter = sb.toString();
    	    	}
    	    }
    	    
    	}
		add(modelName, methodName, parameter, loginUser, ip, fromMenu);
		
	}
	
//	@Async
	private void add(String modelName, String operation, String parameter, LoginUser loginUser, String ip, String fromMenu) {
		if (loginUser == null) return ;
		if (StringUtils.isEmpty(modelName) || StringUtils.isEmpty(operation)) return ; 
		
//		LoginUser loginUser = getUserService().getLoginUser();
		
		Executor<Object, Object[]> regular = this.systemLogRegular.get();
		SystemLog systemLog = null;
		if (regular != null) {
			systemLog = (SystemLog) regular.execute(new Object[] {modelName, operation, fromMenu});
			if (systemLog == null) return ;
		}
		
		if (systemLog == null){
			systemLog = new SystemLog();
			systemLog.setModelName(modelName);
			systemLog.setOperation(operation);
		}
		
		systemLog.setIp(ip);
		systemLog.setParameter(parameter);
		
		systemLog.setLoginUser(loginUser);
		systemLog.setCreationOn(Calendar.getInstance().getTime());
		genericService.merge(systemLog);
	}


	public void registerRegular(Executor<Object, Object[]> regular) {
		this.systemLogRegular.set(regular);		
	}
}
